package api

import (
	"fmt"
	com "go-http/netdisk/common"
	"go-http/netdisk/conf"
	"go-http/netdisk/db"
	"go-http/netdisk/pkg/e"
	"go-http/netdisk/pkg/utils"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
)

const (
	AUTHORIZE_SUCCESS       = 500
	AUTHORIZE_FAILED        = 501
	REGISTER_SUCCESS        = 510
	REGISTER_USERNAME_EXIST = 511
	BIND_PARSE_FAILED       = 550
	DATABASE_FAILED         = 600
)

const (
	COOKIE_DURATION = 24 * 60 * 60 // 单位s
)

type LoginInfo struct {
	// binding: "required" 修饰的字段是必须字段，若接收到的为！！！零值！！！(即使为整型0也不行)，则报错
	// ****** 成员首字母必须大写 ******
	Username string `form:"username" json:"username" uri:"username" xml:"username" binding:"required"`
	Password string `form:"password" json:"password" uri:"password" xml:"password" binding:"required"`
}

// type LoginResponse struct {
// 	Uid
// }

type RegisterInfo struct {
	// binding: "required" 修饰的字段是必须字段，若接收到的为！！！零值！！！(即使为整型0也不行)，则报错，如果确实有零值，转换为指针即可
	// ****** 成员首字母必须大写 ******
	Username string `form:"username" json:"username" uri:"username" xml:"username" binding:"required"`
	Password string `form:"password" json:"password" uri:"password" xml:"password" binding:"required"`
	Phone    string `form:"phone" json:"phone" uri:"phone" xml:"phone"`
	Email    string `form:"email" json:"email" uri:"email" xml:"email"`
	// 因为 Usertype 和 Gender 有合法0值，所以转换为指针！！！！！
	Usertype *uint8 `form:"usertype" json:"usertype" uri:"usertype" xml:"usertype" binding:"required"`
	Gender   *uint8 `form:"gender" json:"gender" uri:"gender" xml:"gender"`
}

// 所有字段首字母必须大写
type User struct {
	Uid           string
	Username      string
	Password      string
	IsAdmin       uint8 `gorm:"default:;"`
	IsGroup       uint8 `gorm:"default:;"`
	CreateTime    time.Time
	UpdateTime    time.Time
	LastLoginTime time.Time `gorm:"default:;"`
	Phone         string    `gorm:"default:;"`
	Email         string    `gorm:"default:;"`
	Gender        uint8
	// Group          Group     `gorm:"foreignkey:Gid"`
	TotalSize      int    `gorm:"default:;"`
	TotalSizeLimit int    `gorm:"default:;"`
	Gid            string `gorm:"default:;"`
}

func UserRefresh(c *gin.Context) {
	tokenString := c.GetHeader("Authorization")
	if tokenString == "" {
		c.JSON(http.StatusUnauthorized, com.ResponseData{Code: e.ERROR_AUTH, Msg: e.GetMsg(e.ERROR_AUTH)})
		return
	}

	claims, err := utils.ParseTokenIgnorExpired(tokenString)
	if err != nil {
		fmt.Printf("parse token:%s err:%s\n", tokenString, err.Error())
		c.JSON(http.StatusUnauthorized, com.ResponseData{Code: e.ERROR_AUTH_CHECK_TOKEN_FAIL, Msg: e.GetMsg(e.ERROR_AUTH_CHECK_TOKEN_FAIL)})
		return
	}

	token, err := utils.GenerateToken(claims.Uid)
	if err != nil {
		c.JSON(http.StatusUnauthorized, com.ResponseData{Code: e.ERROR_AUTH_GENERATE_TOKEN, Msg: e.GetMsg(e.ERROR_AUTH_GENERATE_TOKEN)})
		return
	}

	c.JSON(http.StatusOK, com.ResponseData{
		Code: e.SUCCESS,
		Data: map[string]interface{}{
			"token": map[string]interface{}{
				"token":   token,
				"expired": time.Now().Add(conf.TOKEN_EXPIRES * time.Second).Unix(),
			},
		},
		Msg: e.GetMsg(e.SUCCESS),
	})
}

func UserInfo(c *gin.Context) {
	u := User{}
	if err := db.DB.Find(&u, "uid = ?", c.Keys["uid"]).Error; err != nil {
		fmt.Printf("get user:%s Info err:%s\n", c.Keys["uid"], err.Error())
		c.JSON(http.StatusOK, com.ResponseData{Code: e.ERROR_MYSQL, Msg: e.GetMsg(e.ERROR_MYSQL)})
		return
	}

	c.JSON(http.StatusOK, com.ResponseData{
		Code: e.SUCCESS,
		Data: map[string]interface{}{
			"uid":       u.Uid,
			"username":  u.Username,
			"avaterUrl": "",
			"role":      u.IsAdmin,
			"usertype":  u.IsGroup,
			"gender":    u.Gender,
		},
		Msg: e.GetMsg(e.SUCCESS),
	})
}

func UserLogin(c *gin.Context) {
	info := LoginInfo{}

	if err := c.ShouldBind(&info); err != nil {
		c.JSON(http.StatusUnauthorized, gin.H{"code": BIND_PARSE_FAILED, "err": err.Error()})
		return
	}

	fmt.Printf("login:%#v, sha:%s\n", info, utils.SHA1(info.Password))

	var u User
	// err := db.DB.Where("username = ? AND password = ?", username, password).Find(&u)
	if err := db.DB.Find(&u, "username = ? AND password = ?", info.Username, utils.SHA1(info.Password)).Error; err != nil {
		c.JSON(http.StatusOK, gin.H{"code": AUTHORIZE_FAILED, "msg": err.Error()})
		return
	}

	fmt.Printf("u => %#v\n", u)
	token, err := utils.GenerateToken(u.Uid)
	if err != nil {
		c.JSON(http.StatusUnauthorized, gin.H{"code": AUTHORIZE_FAILED, "msg": err.Error()})
		return
	}

	// c.SetCookie("token", token, COOKIE_DURATION, "/", "localhost", false, false)
	c.JSON(http.StatusOK, com.ResponseData{
		Code: e.SUCCESS,
		Data: map[string]interface{}{
			"user": map[string]interface{}{
				"uid":       u.Uid,
				"username":  u.Username,
				"avaterUrl": "",
				"role":      u.IsAdmin,
				"usertype":  u.IsGroup,
				"gender":    u.Gender,
			},
			"token": map[string]interface{}{
				"token":   token,
				"expired": time.Now().Add(conf.TOKEN_EXPIRES * time.Second).Unix(),
			},
		},
		Msg: e.GetMsg(e.SUCCESS),
	})
}

func UserRegister(c *gin.Context) {
	info := RegisterInfo{}

	if err := c.ShouldBind(&info); err != nil {
		c.JSON(http.StatusUnauthorized, gin.H{"code": BIND_PARSE_FAILED, "msg": err.Error()})
		return
	}

	fmt.Printf("register:%#v\n", info)

	var u User
	if err := db.DB.Select("username = ?", info.Username).First(&u).Error; err == nil {
		// 用户名已存在
		c.JSON(http.StatusOK, gin.H{"code": REGISTER_USERNAME_EXIST, "msg": "Username exist."})
		fmt.Printf("register failed, username:%s exist!!\n", info.Username)
	} else {

		var gender = uint8(0)
		if info.Gender != nil {
			gender = *info.Gender
		}

		tm := time.Now()
		u = User{
			Uid:        utils.NewV4String(),
			Username:   info.Username,
			Password:   utils.SHA1(info.Password),
			CreateTime: tm,
			UpdateTime: tm,
			IsGroup:    *info.Usertype,
			Phone:      info.Phone,
			Email:      info.Email,
			Gender:     gender,
		}

		if err := db.DB.Create(&u).Error; err != nil {
			// fmt.Println("insert user, err:", err)
			c.JSON(http.StatusInternalServerError, gin.H{"code": DATABASE_FAILED, "msg": err.Error()})
		} else {
			c.JSON(http.StatusOK, gin.H{"code": REGISTER_SUCCESS})
		}
	}
}
